//  This file is part of Swordbible - http://www.swordwarrior.net
//  Copyright (C) 2003-2009 Manu Mital mital.manu@gmail.com

//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2, or (at your option)
//  any later version.

//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.

//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


// DailyBiblePage.cpp : implementation file
//

#include <stdafx.h>
#include "SwordBible.h"
#include "DailyBiblePage.h"
#include "BiblePage.h"
#include "BibleForm.h"
#include "CreateReadingPlan.h"
#include <odbcinst.h> 
#include <afxdb.h> 
#include "toolbar/TCImageList.h"
#include "Remove.h"
#include "MainFrm.h"


CStringArray CDailyBiblePage::planNames;
CString      CDailyBiblePage::path;


// CDailyBiblePage dialog

IMPLEMENT_DYNAMIC(CDailyBiblePage, CPropertyPage)

CDailyBiblePage::CDailyBiblePage()
	: CPropertyPage(CDailyBiblePage::IDD)
{
	numRead = 0;
	numTotal = 1;
	month = 1;
	day = 1;
	pModuleActive = NULL;
	active = 0;
	m_pCatalog = NULL;
	m_piAdoRecordBinding = NULL;
	plan = _T(""); // holds the currently active reading plan (used by the function showText)
}

CDailyBiblePage::~CDailyBiblePage()
{

}

void CDailyBiblePage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_RICHEDIT_DB, m_rich);
	DDX_Control(pDX, IDC_DB_CALENDAR, DBCalendarCtrl);
	DDX_Control(pDX, IDC_STATIC_CRYSTAL, CrystalCal);
	DDX_Control(pDX, IDC_RICHEDIT_DATE, m_richeditDate);

	DDX_Control(pDX, IDC_CHECK_READ, readCtrl);
	DDX_Control(pDX, IDC_RICHEDIT_NAME, PlanNameCtrl);
	DDX_Control(pDX, IDC_PROGRESS_DB, DBProgress);
}


BEGIN_MESSAGE_MAP(CDailyBiblePage, CPropertyPage)
	ON_COMMAND(ID_DAILYBIBLE_PRINT,OnPrint)
	ON_COMMAND(ID_DAILYBIBLE_COPY, OnCopy)
	ON_COMMAND(ID_DAILYBIBLE_SELECTALL, OnSelectAll)
	ON_COMMAND(ID_DAILYBIBLE_PREVIOUSDATE,OnPreviousDate)
	ON_COMMAND(ID_DAILYBIBLE_NEXTDATE,OnNextDate)
	ON_COMMAND(ID_DB_VERSIONS, OnShowVersions)
	ON_COMMAND(ID_DB_PLANS, OnChangeReadingPlans)
	ON_COMMAND(ID_DAILYBIBLE_ZOOM, OnZoom)
	ON_UPDATE_COMMAND_UI(ID_DAILYBIBLE_ZOOM, OnUpdateZoom)
	ON_COMMAND(ID_DB_ADDPLANS, OnAddPlan)
	ON_COMMAND(ID_DB_DELPLANS,  OnRemovePlan)
	


	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)

    ON_WM_SIZE()
     ON_NOTIFY(MCN_SELCHANGE, IDC_DB_CALENDAR, &CDailyBiblePage::OnSelCalendar)
	 ON_NOTIFY(EN_MSGFILTER, IDC_RICHEDIT_DB, &CDailyBiblePage::OnEnMsgfilter)

	 ON_EN_SETFOCUS(IDC_RICHEDIT_DATE, &CDailyBiblePage::OnFocusRichEditDate)
	 ON_EN_SETFOCUS(IDC_RICHEDIT_NAME, &CDailyBiblePage::OnFocusRichName)
	 ON_WM_DESTROY()
	 ON_BN_CLICKED(IDC_CHECK_READ, &CDailyBiblePage::OnCheckRead)
END_MESSAGE_MAP()


// CDailyBiblePage message handlers


BOOL CDailyBiblePage::OnInitDialog()
{
	CPropertyPage::OnInitDialog();

	//set the icon for the dialog
	SetIcon(::AfxGetApp()->LoadIcon(IDR_MAINFRAME), TRUE);

	if(CBiblePage::font.location != AFX_MAINBIBLE)   // this can happen if there are no bibles
	{
	CBiblePage::font.location = AFX_MAINBIBLE;
	CBiblePage::font.Load();
	CBiblePage::font.ConstructRTF();
	}

	
	m_rich.SetBackgroundColor(FALSE, CColorMgr::RTFtoCOLORREF(CBiblePage::font.bg_color) );

	CString text = CBiblePage::font.GetHeaderRTF();

	

	if (!m_wndFormatBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD
       | WS_VISIBLE | CBRS_TOP |  CBRS_FLYBY | CBRS_TOOLTIPS) ||
       !m_wndFormatBar.LoadToolBar(IDR_DAILYBIBLE_TOOLBAR))
   {
      TRACE0("Failed to create toolbar\n");
      return -1;      // fail to create
   }

	m_wndFormatBar.LoadTCToolBar(24, IDB_TOOLBAR_DB,IDB_TOOLBAR_DB,
                              IDB_TOOLBAR_DB, RGB(255,255,255));


	// Position the control bars using RepositionBars. 
	RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);

		

	// Expand the size of the Toolbar window so all controls in it would fit	
	CRect toolBarRect;
	CToolBarCtrl& formatBar = m_wndFormatBar.GetToolBarCtrl();
	formatBar.GetWindowRect(toolBarRect);
	ScreenToClient(toolBarRect);
	toolBarRect.left = 10;
	toolBarRect.right += 600;
	formatBar.MoveWindow(toolBarRect,TRUE);

	// diable the 16 ID_PLACEHOLDER BUTTONS
	  for(int n = 0; n < 16; n++)
	formatBar.SendMessage((UINT) TB_ENABLEBUTTON, (WPARAM)(int) ID_PLACEHOLDER1 + n,  (LPARAM) MAKELONG(FALSE, 0) );


    EnableToolTips();   // enable tool tips for view
 
	m_rich.SetEventMask(ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_SCROLLEVENTS);
	m_rich.SendMessage(EM_EXLIMITTEXT,0,-1);
	
  
	/*********************** DATABASE stuff: the VerseLists uses different database file as the notes page ****/
	////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/*************************************************************************************************************/

	 IsAppData = TRUE;   // start by assuming that the notes database file exists

   CBibleSheet::GetAppDirectory(path);
	

  #if defined VERSION_PORTABLE
  path.Replace(_T("\\App\\SwordBible"),  _T("\\Data\\Data.mdb"));
  #else
   path = (CString) path.GetAt(0) + _T(":\\Data.mdb");
  #endif

	
	TCHAR * pChar = new TCHAR[400];
	memset(pChar, 0, 400);
	_stprintf(pChar, _T("Provider='Microsoft.JET.OLEDB.4.0';Data source = %s"),path);
	m_strConnection = pChar;
	delete [] pChar;

	CreateDB();  // configure a user's machine to use MS access

	

	if(GetFileAttributes(path) == -1)
	 { 
		
	  // call the VerseLists Dialog to create the file
		 
		 // create the verse list window if it does not exist
		if (!CMainFrame::m_pModelessVL)
       CMainFrame::m_pModelessVL= new CVerseLists;

		 if (!::IsWindow(CMainFrame::m_pModelessVL->GetSafeHwnd()))
	   CMainFrame::m_pModelessVL->Create(IDD_VERSELISTS, (CMainFrame*) AfxGetApp()->GetMainWnd() );
			
	   // has the database file been created successfully ? Check in the next step
	    
	}


	if(GetFileAttributes(path) == -1)
	 IsAppData = FALSE;

	
  ////////////////////////////////////////// END DATABASE STUFF /////////////////////////////////////////////////
	 /////////////////////////////////////////////////////////////////////////////////////////////////////
   AddPlanNames();


	 // set the active module
   active = CBiblePage::active;
	pModuleActive = CSwordBibleDoc::pRTFBibleModule[active];


  CTime time;
	DBCalendarCtrl.GetToday(time);
	
	// set the key
	month  = time.GetMonth();
	day = time.GetDay();
	year = time.GetYear();
	timeKey.Format(_T("%.2d%.2d%.4d"),month, day,year);
	timeFormatted = time.Format(_T("%B %d"));


	DBProgress.SetShowPercent(FALSE);
	DBProgress.SetRange(0,100);
	COLORREF cr = DBProgress.GetBarBkColor();
	CString bc = AfxGetApp()->GetProfileString(_T("Devotional"), _T("DBProgressColor"), CColorMgr::COLORREFtoRTF(cr)  );
	cr = CColorMgr::RTFtoCOLORREF(bc);
	DBProgress.SetBarBkColor(cr);

				

	// select a reading plan
	if( planNames.GetCount() )
	{
	plan = planNames[0];
	SelectTable(plan);

	//show the day's bible text
	showText();

	ComputePercentComplete();
	UpdateProgress();

	}

	else UpdateCalendarDate();

	
	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}


// displays the text in the rich edit box of the one year bible
void CDailyBiblePage::showText()
{
	if(!pModuleActive) return;
	if(planNames.GetCount() <= 0) return;

    CBibleSheet::DisableStrongMorph();

  // clear limits
	Footnotes.RemoveAll();
	Xrefs.RemoveAll();
	XLimits.Clear();
	
	sword::VerseKey vk;	
	GetReadingData(timeKey);
	CString parse = Data;  //<--- Data has been updated after call to GetReadingData

	sword::ListKey lk = vk.ParseVerseList( (CStringA) parse, vk, true );

	
	
		CString chapText = CBiblePage::font.GetHeaderRTF();
		

		CString titleSize;
		titleSize.Format(_T("\\cf2\\fs%d "), CBiblePage::font.text_facesize + 5);
		chapText = chapText +  titleSize + (CString) pModuleActive->Description();
		
		// reset the font size
		titleSize.Format(_T("\\fs%d"), CBiblePage::font.text_facesize);
		chapText = chapText + titleSize + _T(" ");
	

		lk = sword::TOP;
		sword::VerseKey key = lk;
		int chap = key.Chapter(), book = key.Book();
		int old_chap = -1, old_book = -1;
		CString Verse, Chapter;
				
	// get the text line by line
		for (lk = sword::TOP; !lk.Error(); lk++) {

    pModuleActive->SetKey(lk);         // set key to current verse
		key = lk;
			chap = key.Chapter();
		    book = key.Book();
			Verse.Format(_T("%d"),key.Verse());
		    Chapter.Format(_T("%d"),chap);
			
	
			if(   !(chap == old_chap && book == old_book)  )			
               	chapText += _T("\\par\\par\\cf1\\b ") + (CString) key.getBookName() + _T(" ") + Chapter +  _T("\\b0\\par\\par ");
			
		
			if(CSwordBibleDoc::heading_tags)  AddHeadings(chapText); // Add headings
			
			// the verse use the color cf1 in the color table
			chapText = chapText +  _T("\\super\\cf1\\b ") + Verse + _T(" \\b0\\nosupersub ");

			// the text uses the color cf2 in the color table
			chapText += _T("\\cf2 ");
		
      CString renderText = (CString) pModuleActive->RenderText();
      renderText.Replace(_T("\\cf6"),_T("\\cf9"));

			chapText += renderText;

      if(CSwordBibleDoc::fn_tags) AddFootNotes(renderText, key.Verse());
			if(CSwordBibleDoc::crossref_tags) AddXref(renderText, key.Verse());

			old_chap = chap; old_book = book;
			
				
		}

      CBibleSheet::RestoreStrongMorph();

    	// Append the footnotes
		int count = Footnotes.GetCount();

		if(count)
		{
		chapText += _T("\\par\\cf5\\\ul Footnotes:\\ul0\\par\\sub ");	
		for(int i = 0; i < count ; i++) chapText = chapText + (CString) pModuleActive->RenderText((CStringA) Footnotes.GetAt(i)) + _T("\\par ");
		}


		chapText += _T("}");

		chapText.Replace(_T("<a href=\"\">*n"),  _T("\\cf5\\b *n"));
		chapText.Replace(_T("<a href=\"\">*x"),  _T("\\cf6\\b *x"));
		chapText.Replace(_T("</a>"), _T("\\cf2\\b0 "));
		chapText.Replace(_T("<a href=\"\">"),  _T(" "));
		
		//DWORD one = GetTickCount();
		m_rich.SetRTF(chapText);
		//DWORD two = GetTickCount();
		
		m_rich.SetFocus();


	//	CString temp;
	//	temp.Format("time was %d, total time was %d", two - one, two - zero);
	//	AfxMessageBox(temp);
	

		ZoomText();

		// change the date on the calendar picture
		UpdateCalendarDate();

    if(CSwordBibleDoc::crossref_tags) SetXLimits();

		//update the check box <--- the variable isRead has been updated after call to GetReadingData
		// at the beginning of showText()
		if(isRead == _T("R")) readCtrl.SetCheck(TRUE);
		else readCtrl.SetCheck(FALSE);
		readCtrl.UpdateData(FALSE);

		

	
}

void CDailyBiblePage::UpdateCalendarDate()
{
	CString picDate;
	picDate.Format(_T("{\\rtf1{\\fonttbl {\\f1 Arial;}}\\f1\\fs22\\b %s \\par\\fs60 %d \\b0 }"), 
			(LPCTSTR) CSwordBibleDoc::monthNames[month - 1], day);
	m_richeditDate.SetRTF(picDate);

}

// add pre-verse headings to the beginning of each verse
void CDailyBiblePage::AddHeadings(CString& Text)
{
		int pvHeading = 0;
		char buf[10];
		BOOL heading = TRUE;
		
		while(heading == TRUE){
		sprintf(buf, "%i", pvHeading++);
		sword::SWBuf pvh = pModuleActive->getEntryAttributes()["Heading"]["Preverse"][buf].c_str(); 

		CString preverseHeading = (CString) pModuleActive->RenderText(pvh);

		if(preverseHeading.GetLength() < 2) heading = FALSE;
		else Text = Text + _T("\\par\\par\\cf2\\b\\i ") + preverseHeading + _T("\\i0\\b0\\par\\par ");
		}

}

void CDailyBiblePage::AddFootNotes(CString& VerseText, int verse)
{
	
	int found  = 0;
	int index  = 1;

	CString findtext;
	CString verseStr;
	CString indexStr;
	CStringArray fn_label;
	CString fntext;



	verseStr.Format(_T("%d"), verse);

	for(index = 1; index < 15; index++)
	{
	indexStr.Format(_T("%d"), index);
	findtext = _T("*n") + verseStr + _T(".") + indexStr;

	found = VerseText.Find(findtext);

	if(found != -1) fn_label.Add(findtext);
		
	}


	int c = 0;
	int count = fn_label.GetCount();
	
	sword::AttributeList &fnl = pModuleActive->getEntryAttributes()["Footnote"]; 

	for (sword::AttributeList::iterator& it = fnl.begin(); it != fnl.end() && c < count; it++) 
	{
		fntext= it->second["body"];
		if(fntext.GetLength() > 1 && it->second["type"] != "crossReference" )	Footnotes.Add( fn_label.GetAt(c++) + " " + fntext );
	}
					
}

void CDailyBiblePage::AddXref(CString& VerseText, int verse)
{
	
	int found  = 0;
	int index  = 1;

	CString findtext;
	CString verseStr;
	CString indexStr;
	CStringArray x_label;
	

	verseStr.Format(_T("%d"), verse);

	for(index = 1; index < 15; index++)
	{
	indexStr.Format(_T("%d"), index);
	findtext = _T("*x") + verseStr + _T(".") + indexStr;

	found = VerseText.Find(findtext);

	if(found != -1) x_label.Add(findtext);		
	}


	int c = 0;
	int count = x_label.GetCount();
	sword::AttributeList &xrefl = pModuleActive->getEntryAttributes()["Footnote"]; 

	for (sword::AttributeList::iterator& it = xrefl.begin(); it != xrefl.end() && c < count; it++) 
	{
		CString xtext= (CString) it->second["refList"];
		if(xtext.GetLength() >= 2)	Xrefs.Add( x_label.GetAt(c++) + _T("$$$") + xtext );
	}
								
	
					
}

void CDailyBiblePage::SetXLimits()
{
	int count = Xrefs.GetCount();
	FINDTEXTEX ft1;
	ft1.chrg.cpMin = 0;
	ft1.chrg.cpMax = -1;
	int pos;
	CString left, right;
	int start, end;


	for(int i =0; i < count; i++)
	{
		CString str = Xrefs.GetAt(i);
		pos = str.Find(_T("$$$"));
		left = str.Left(pos);
		right = str.Mid(pos + 3);

		ft1.lpstrText = left;

		start = m_rich.FindText(FR_DOWN , &ft1);
		end = start + left.GetLength() - 1;

		XLimits.Add(start, end, right);

		ft1.chrg.cpMin = start + 1;

	}
}








BOOL CDailyBiblePage::OnToolTipNotify(UINT id, NMHDR *pNMHDR,   LRESULT *pResult)
{
   ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);

     // if there is a top level routing frame then let it handle the message
     if (GetRoutingFrame() != NULL) return FALSE;

     // to be thorough we will need to handle UNICODE versions of the message also !!
     TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
     TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
     TCHAR szFullText[512];
     CString strTipText;
     UINT nID = pNMHDR->idFrom;

     if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
         pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
     {
          // idFrom is actually the HWND of the tool 
          nID = ::GetDlgCtrlID((HWND)nID);
     }

     if (nID != 0) // will be zero on a separator
     {
          AfxLoadString(nID, szFullText);
          strTipText=szFullText;

#ifndef _UNICODE
          if (pNMHDR->code == TTN_NEEDTEXTA)
          {
               lstrcpyn(pTTTA->szText, strTipText, sizeof(pTTTA->szText));
          }
          else
          {
               _mbstowcsz(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
          }
#else
          if (pNMHDR->code == TTN_NEEDTEXTA)
          {
               _wcstombsz(pTTTA->szText, strTipText,sizeof(pTTTA->szText));
          }
          else
          {
               lstrcpyn(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
          }
#endif

          *pResult = 0;

          // bring the tooltip window above other popup windows
          ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,SWP_NOACTIVATE|
               SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER); return TRUE;
     }
      return FALSE;
}

void CDailyBiblePage::OnSize(UINT nType, int cx, int cy)
{
	CPropertyPage::OnSize(nType, cx, cy);
	
	pt.x = cx - 148; pt.y = 215;

	if(DBCalendarCtrl.GetSafeHwnd())
	DBCalendarCtrl.SetWindowPos(NULL,cx - 180,40,174,154,SWP_NOZORDER | SWP_NOACTIVATE);

	if(m_rich.GetSafeHwnd()) 
	m_rich.SetWindowPos(NULL,10,40,cx-200,cy-50,SWP_NOZORDER | SWP_NOACTIVATE);

	if(readCtrl.GetSafeHwnd())
	readCtrl.SetWindowPos(NULL, pt.x + 10, pt.y + 120, 108, 24, SWP_NOZORDER | SWP_NOACTIVATE);
	
	if(m_richeditDate.GetSafeHwnd()) 
	m_richeditDate.SetWindowPos(NULL,pt.x + 1, pt.y + 38,102 ,70 ,SWP_NOZORDER | SWP_NOACTIVATE);

	if(CrystalCal.GetSafeHwnd()) 
	CrystalCal.SetWindowPos(NULL,pt.x, pt.y ,108,119 ,SWP_NOZORDER | SWP_NOACTIVATE);

	if(PlanNameCtrl.GetSafeHwnd() )
	PlanNameCtrl.SetWindowPos(NULL, cx- 180 ,400 , 174, 30 ,SWP_NOZORDER | SWP_NOACTIVATE);

	if(DBProgress.GetSafeHwnd())
	{
	DBProgress.SetWindowPos(NULL, cx- 180 ,438 , 174, 30 ,SWP_NOZORDER | SWP_NOACTIVATE);
     DBProgress.Invalidate();
	}

	// to prevent fluctuation, we redraw only the relevant portion of the screen
	 InvalidateRect( CRect(pt.x - 5, pt.y -5, pt.x + 115, pt.y + 120));


}

void CDailyBiblePage::OnPrint()
{
	// only the active page should handle the message
     if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
		 return;

	CBibleForm::pControl = (CRichEditCtrl *) GetDlgItem(IDC_RICHEDIT_DB);
	AfxGetMainWnd()->SendMessageToDescendants(WM_PRINT_CONTROL, (WPARAM) 1 , 0);
  
}

void CDailyBiblePage::OnCopy(void) 
{
 // only the active page should handle the message
  if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;

	m_rich.Copy();

}

void CDailyBiblePage::OnSelectAll(void) 
{
			// only the active page should handle the message
  if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;

  m_rich.SetFocus();
  m_rich.SetSel(0,-1);

}


void CDailyBiblePage::OnZoom()
{
	// only the active page should handle the message
		if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;


	CSwordBibleDoc::dailybibleZoom = !(CSwordBibleDoc::dailybibleZoom);

	ZoomText();

	// set or remove the check
	m_wndFormatBar.SendMessage((UINT) TB_CHECKBUTTON, (WPARAM)(int) ID_DAILYBIBLE_ZOOM, 
		(LPARAM) MAKELONG(CSwordBibleDoc::dailybibleZoom, 0) );


}

// this function is never called 

void CDailyBiblePage::OnUpdateZoom(CCmdUI *pCmdUI)
{
	pCmdUI->SetCheck(CSwordBibleDoc::dailybibleZoom);
    
		
}




void CDailyBiblePage::ZoomText()
{
	if(CSwordBibleDoc::dailybibleZoom) m_rich.SendMessage(EM_SETZOOM, 5,4); //zoom by 1.25
	else m_rich.SendMessage(EM_SETZOOM, 0,0);  // turn off zooming

}


void CDailyBiblePage::OnPreviousDate()
{


    CTime time;
	DBCalendarCtrl.GetCurSel(time);
	time = time - CTimeSpan(1,0,0,0);
	DBCalendarCtrl.SetCurSel(time); // set new time

		// set the key
	month  = time.GetMonth();
	day = time.GetDay();
	year = time.GetYear();
	timeKey.Format(_T("%.2d%.2d%.4d"),month, day,year);
	timeFormatted = time.Format  (_T("%B %d"));

	showText();   // update display

}

void CDailyBiblePage::OnNextDate()
{
 
    CTime time;
    DBCalendarCtrl.GetCurSel(time);         // Get current time
	time = time + CTimeSpan(1,0,0,0);
	DBCalendarCtrl.SetCurSel(time); // set new time

		// set the key
	month  = time.GetMonth();
	day = time.GetDay();
	year = time.GetYear();
	timeKey.Format(_T("%.2d%.2d%.4d"),month, day,year);
	timeFormatted = time.Format  (_T("%B %d"));

   showText();   // update display
	
}


void CDailyBiblePage::OnShowVersions()
{

	RECT rc;
    m_wndFormatBar.GetToolBarCtrl().GetItemRect(0,&rc);
	m_wndFormatBar.ClientToScreen(&rc); // TrackPopupMenu uses screen coords

   CMenu menu;
   menu.CreatePopupMenu();
   CMenu* pPopup = NULL;
   pPopup = &menu;

   if(pPopup == NULL) return;
   int dwSelectionMade;  

 
   // fill in the strings for different bible versions
	for(int i = 0; i < CSwordBibleDoc::numBiblesAvailable; i++)
		if(CSwordBibleDoc::pRTFBibleModule[i] != NULL)
		{
			         pPopup->AppendMenu(MF_STRING,ID_BIBLEVERSION_NAMES + i, (CString) CSwordBibleDoc::pRTFBibleModule[i]->Description());
					 if(active == i) pPopup->CheckMenuItem(ID_BIBLEVERSION_NAMES + i,MF_CHECKED); 

		}


         dwSelectionMade =  pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON|TPM_RETURNCMD, 
         rc.left, rc.bottom + 4, this);

	
		int selection = dwSelectionMade;
		int base = ID_BIBLEVERSION_NAMES;
		int sel = selection - base;


	if(sel >=0 && sel < CSwordBibleDoc::numBiblesAvailable) 
	{
		active = sel;

		pModuleActive = CSwordBibleDoc::pRTFBibleModule[active];
		showText();
	}

    pPopup->DestroyMenu(); 


}


void CDailyBiblePage::OnChangeReadingPlans()
{


	RECT rc;
    m_wndFormatBar.GetToolBarCtrl().GetItemRect(1,&rc);
	ClientToScreen(&rc); // TrackPopupMenu uses screen coords

   CMenu menu;
   menu.CreatePopupMenu();
   CMenu* pPopup = NULL;
   pPopup = &menu;

   if(pPopup == NULL) return;
   int dwSelectionMade;  

 
   // fill in the strings for different bible versions
	for(int i = 0; i < planNames.GetCount(); i++)
	{
			         pPopup->AppendMenu(MF_STRING,ID_READINGPLAN_NAMES + i,  planNames.GetAt(i)  );
					 if( planNames.GetAt(i) ==  plan ) pPopup->CheckMenuItem(ID_READINGPLAN_NAMES + i,MF_CHECKED); 

		}


         dwSelectionMade =  pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON|TPM_RETURNCMD, 
         rc.left + 2, rc.bottom + 4, this);

	
		int selection = dwSelectionMade;
		int base = ID_READINGPLAN_NAMES;
		int activate = selection - base;


	if(activate >= 0 && activate < planNames.GetCount() ) 
	{
		plan = planNames[activate];
		SelectTable(plan);
		showText();

		ComputePercentComplete();
		UpdateProgress();

	}
    pPopup->DestroyMenu(); 


}




void CDailyBiblePage::OnSelCalendar(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMSELCHANGE pSelChange = reinterpret_cast<LPNMSELCHANGE>(pNMHDR);

	CTime time;
	DBCalendarCtrl.GetCurSel(time); 

	// set the key
	month  = time.GetMonth();
	day = time.GetDay();
	year = time.GetYear();
	timeKey.Format(_T("%.2d%.2d%.4d"),month, day,year);
	timeFormatted = time.Format  (_T("%B %d"));
		
	showText();

	*pResult = 0;
}


void CDailyBiblePage::OnEnMsgfilter(NMHDR *pNMHDR, LRESULT *pResult)
{
	MSGFILTER *pMsgFilter = reinterpret_cast<MSGFILTER *>(pNMHDR);

  if(pMsgFilter->msg == WM_MOUSEMOVE)
	{ 
		CPoint point;                                            
    ::GetCursorPos(&point); //where is the mouse?


		 // change the coordinates of the point from Screen to that of richedit
		m_rich.ScreenToClient(&point);

		int nchar =  m_rich.CharFromPos(point);

		CString keylist = _T("");
    CString number = _T("");
		int lower = 0, upper = 0;
		if(XLimits.FromPos(nchar, lower, upper, number) == TRUE) 
		SetCursor(CBibleSheet::m_hHandCursor);
	}


	
	else if (pMsgFilter->msg == WM_RBUTTONDOWN)   OnRightButtonDown();
  else if(pMsgFilter->msg == WM_LBUTTONDOWN) OnLeftButtonDown();

	*pResult = 0;
}

void CDailyBiblePage::OnLeftButtonDown()
{

 	 CPoint point;                                            
   ::GetCursorPos(&point); //where is the mouse?

		 // change the coordinates of the point from Screen to that of richedit
		m_rich.ScreenToClient(&point);

		int nchar =  m_rich.CharFromPos(point);
    CString number = _T("");
		CString tip = _T("");
		int lower = 0, upper = 0;

    if(XLimits.FromPos(nchar, lower, upper, number))
		 {
	
			 CString dlgTitle =  _T("Scripture Cross-reference");       
       CBiblePage::DisplayReferenceVerses(number, tip);
		   CBibleSheet::DisplayReference(dlgTitle, tip);
		 }

}
	


void CDailyBiblePage::OnRightButtonDown()
{

	  CPoint point;                                            
     ::GetCursorPos(&point); //where is the mouse?
     CMenu menu; //lets display out context menu :) 
     DWORD dwSelectionMade;                                       
     VERIFY(menu.LoadMenu(_T("IDR_MENU_DAILYBIBLEPAGE") ));  
     CMenu *pmenuPopup = menu.GetSubMenu(0);
     ASSERT(pmenuPopup != NULL);   

	  if(CSwordBibleDoc::dailybibleZoom)	pmenuPopup->CheckMenuItem(ID_DAILYBIBLE_ZOOMTEXT,MF_CHECKED); 

	    // get the word under mouse
	  CPoint pt = point;
	  m_rich.ScreenToClient(&pt);     // change the coordinates of the point from Screen to that of richedit
	  CString text = _T("");
	  CBiblePage::GetWordUnderMouse(&m_rich, pt, text);   

      CString ltext = _T("Lookup: ");
      CString stext = _T("Search for: ");

	  if(text.GetLength() > 1) {
		  ltext += text;
		  pmenuPopup->ModifyMenu(0, MF_BYPOSITION|MF_STRING, ID_DAILYBIBLE_DICT_LOOKUP, ltext);

		  stext += text;
		  pmenuPopup->ModifyMenu(1, MF_BYPOSITION|MF_STRING, ID_DAILYBIBLE_SEARCH, stext);

	  }
  
		

     dwSelectionMade = pmenuPopup->TrackPopupMenu( (TPM_LEFTALIGN|TPM_LEFTBUTTON|
                                                      TPM_RETURNCMD),
                                                    point.x, point.y, this); 

	

	
	switch (dwSelectionMade)
	{
	case ID_DAILYBIBLE_PRINT:		OnPrint(); break;
	case ID_DAILYBIBLE_COPY:		OnCopy(); break;
	case ID_DAILYBIBLE_SELECTALL:   OnSelectAll(); break;
	case ID_DAILYBIBLE_ZOOMTEXT:    OnZoom(); break; 
	case ID_DAILYBIBLE_PREVIOUS:    OnPreviousDate(); break;
	case ID_DAILYBIBLE_NEXT:        OnNextDate(); break;
	case ID_DAILYBIBLE_DICT_LOOKUP:  CBiblePage::OnLookupDict(text); break;
	case ID_DAILYBIBLE_SEARCH:       CBiblePage::OnRightClickSearch(this, AFX_MAINBIBLE, active, text);

	}

	
	pmenuPopup->DestroyMenu(); 



}

void CDailyBiblePage::OnAddPlan()
{

	CCreateReadingPlan dlg;
	if( dlg.DoModal() != IDOK) return;

	// we have previously checked to make sure that table name being added is unique 
	if( AddTable(CCreateReadingPlan::newPlanName,_T("ReadingDate"),_T("isRead"), _T("Data")) == FALSE) return;   // table not added


	//Select the newly created table
	SelectTable(CCreateReadingPlan::newPlanName);


	try { // Add the daily readings to this table

	int count = CCreateReadingPlan::dateArray.GetCount();

	for(int i = 0; i < count; i++)
	{
	AddNew();

	Data = CCreateReadingPlan::DailyReadingsArray.GetAt(i);
	isRead = _T("U");
	ReadingDate = CCreateReadingPlan::dateArray.GetAt(i);

	
	UpdateBoundData();
	m_piAdoRecordBinding->Update(&m_rsRecSet);
	}

	planNames.Add(CCreateReadingPlan::newPlanName);
	plan = CCreateReadingPlan::newPlanName;

	// the table has been added and filled
	// set the index key
	if(m_pRs->State == adStateOpen)	m_pRs->Close(); 	

	m_strCmdText.Format(_T("CREATE UNIQUE INDEX IDX_DBTABLE on [%s] (ReadingDate)"), plan); 
		ADOCG::_ConnectionPtr con = m_pCatalog->GetActiveConnection();    // m_pRs should not be NULL
		if(con) con->Execute(m_strCmdText.AllocSysString() , NULL, adExecuteNoRecords);

	SelectTable(plan);	

	showText();

	ComputePercentComplete();
	UpdateProgress();
	}
	
	

	  // Any errors?
     catch (_com_error &e)
     {         // Generate an error message
         GenerateError(e.Error(), e.Description());
	 }

	



	

}

void CDailyBiblePage::OnRemovePlan()
{
	int count = planNames.GetCount();

	if(!count) return; // no plans to remove

	CRemove dlg;
	dlg.icon = _T("folder");
	dlg.type = _T("single");
	dlg.arr.RemoveAll();  // empty the array

	// add plan names to the remove dialog
	for(int i = 0; i < count; i++)
		dlg.arr.Add( planNames.GetAt(i) );

	if(dlg.DoModal() != IDOK) return;

	int sel = -1;
	BOOL found = FALSE;

	// find index of item that was selected
	for(int i = 0; i < count && found == FALSE; i++)
		if(planNames.GetAt(i) == dlg.modList)
		{ 
			sel = i;
			found = TRUE;
		}


		
	if(sel < 0 ||  sel > planNames.GetCount() )  return;


	if( MessageBox(_T("\t") + planNames.GetAt(sel) + _T("\n\n") +
		_T("Are you sure you want to remove the selected plan?"),_T("SwordBible"),MB_OKCANCEL|MB_ICONASTERISK)!= IDOK)
		return;

	     CString toRemove = planNames.GetAt(sel);

		if( DeleteTable( toRemove) == FALSE) return;   // delete the table from database
		planNames.RemoveAt(sel);              // delete the name from the list


		if(planNames.GetCount() <= 0) 
		{
			plan = _T("");
			numRead = 0;
			numTotal = 1;
			UpdateProgress();
			m_rich.SetRTF(_T("")); 
			return;
		}
		
		if(toRemove == plan)           // if the table to be deleted is currently active
		plan = planNames.GetAt(0);                  // make the first plan active
		
		
		SelectTable(plan);               //either the first 
		showText();
		ComputePercentComplete();
		UpdateProgress();
		

}

BOOL CDailyBiblePage::PreTranslateMessage(MSG* pMsg)
{
	if(pMsg->hwnd == GetDlgItem(IDC_PROGRESS_DB)->m_hWnd)
		if(pMsg->message == WM_LBUTTONDOWN)
		{
			CColorDialog dlg;
			if( dlg.DoModal() == IDOK )
			{	

				DBProgress.SetBarBkColor(dlg.GetColor());
				DBProgress.Invalidate();

				// save to registry
				AfxGetApp()->WriteProfileString(_T("Devotional"), _T("DBProgressColor"), CColorMgr::COLORREFtoRTF(dlg.GetColor()) );
			}

		}
	

	return CPropertyPage::PreTranslateMessage(pMsg);
}


// we do not want the rich edit displaying the date (inside calendar picture) to gain
// input focus. so, set the focus back to main rich edit control
void CDailyBiblePage::OnFocusRichEditDate()
{
	m_rich.SetFocus();
}


void CDailyBiblePage::OnFocusRichName()
{
		m_rich.SetFocus();
}



// update the name of the current reading plan and the progress control
void CDailyBiblePage::UpdateProgress()
{

	
		CString name;
		name.Format(_T("{\\rtf1{\\fonttbl {\\f1 Verdana;}}\\f1\\fs18\\b %s\\b0\\par %d/%d}"),  (LPCTSTR) plan, numRead, numTotal);
		PlanNameCtrl.SetRTF(name);
		
		CRect rect;
    	PlanNameCtrl.GetWindowRect(&rect);
		ScreenToClient(rect);
		InvalidateRect(rect);

		CString percentage;
		int p = numRead * 100/numTotal;
		DBProgress.SetPos(p);
	

		percentage.Format(_T("Completed %d percent"), p);
		DBProgress.SetWindowText(percentage);
		DBProgress.Invalidate();
	

}

// called when the user clicks on the check mark
void CDailyBiblePage::OnCheckRead()
{
	if(planNames.GetCount() < 1) return;  // no active plans

	BOOL state = readCtrl.GetCheck();
	CString read;

	if(state  == TRUE)
	{ 
		numRead++;
		read = _T("R");
	}

	else 
	{
		numRead--;
		read = _T("U");
	}




	//write the changes to the database
	GetReadingData(timeKey);
	SaveReadingData(timeKey, read, Data);


	UpdateProgress();


	
}




/////////////////////////////////////// DATABASE FUNCTIONS ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////

BOOL CDailyBiblePage::CreateDB() 

{
	// programmatically configure a user's machine to use access database

	TCHAR* szDesc;
	int mlen;
	szDesc = new TCHAR[256];

	CString csPath = path;

	_stprintf(szDesc,_T("DSN=%s; DESCRIPTION=%s; DBQ=%s; FIL=MicrosoftAccess; DEFAULTDIR=%s"),  _T("SwordBibleDSN"), _T(""),
	csPath	, _T(""));
	mlen = _tcsclen(szDesc);
	for (int i = 0; i < mlen; i++)
	{
		if (szDesc[i] == _T(';'))
			szDesc[i] = _T('\0');
	}
	
	BOOL bOk = SQLConfigDataSource(NULL, ODBC_ADD_DSN, _T("Microsoft Access Driver (*.mdb)\0"), (LPCTSTR)szDesc);
	if(!bOk)
		::AfxMessageBox(_T("Failed"), MB_OK);

	delete [] szDesc;
	return bOk;
	
	
}



//------------------------------------------------------------//
//CreateDatabaseX                                
//Purpose:  create a new Jet database with the Create method
//------------------------------------------------------------// 
void CDailyBiblePage::CreateDatabaseX()
{    
    HRESULT hr = S_OK;

    // These are in the ADOX::  namespace.
    

    try
    {//Open the catalog

		TESTHR(hr = m_pCatalog.CreateInstance(__uuidof(ADOX::Catalog)));
	    m_pCatalog->Create(  m_strConnection.AllocSysString() );          // m_strConnection should be set before calling CreateDatabaseX
	
				
    }
    catch(_com_error &e)
    {
        // Notify the user of errors if any.
        _bstr_t bstrSource(e.Source());
        _bstr_t bstrDescription(e.Description());
          
        _tprintf(_T("\n\tSource :  %s \n\tdescription : %s \n "),
            bstrSource, bstrDescription);

    }
    catch(...)
    {
        AfxMessageBox(_T("Error occured in CreateDatabaseX...."));
    }

}




BOOL CDailyBiblePage::AddTable(CString TableName, CString C1, CString C2, CString C3)
{

	if(IsAppData == FALSE)
		return FALSE;    // no point in continuing if database DNE
	

	try{

	ADOX::_TablePtr m_pTable = NULL;

	if(m_pCatalog == NULL)
	{
		HRESULT hr = S_OK;
		TESTHR(hr = m_pCatalog.CreateInstance(__uuidof(ADOX::Catalog)));
		m_pCatalog->PutActiveConnection(m_strConnection.AllocSysString() );
	}

	/* add the table for the reading plan */
	TESTHR(m_pTable.CreateInstance(__uuidof(ADOX::Table)));
	m_pTable->PutName( TableName.AllocSysString() );
	m_pTable->Columns->Append(C1.AllocSysString(),  ADOX::adVarWChar,   50);
	m_pTable->Columns->Append(C2.AllocSysString(),  ADOX::adVarWChar,   2);
	m_pTable->Columns->Append(C3.AllocSysString(), ADOX::adLongVarWChar,65000);
	
	

	m_pCatalog->Tables->Append(
	_variant_t((IDispatch *)m_pTable));
	m_pCatalog->Tables->Refresh();
	////////////////////////////////////////////////////

	
	}

	catch(...)
    {
        AfxMessageBox(_T("Error occured in CreateTable...."));
		return FALSE;
    }

	return TRUE;




}

BOOL CDailyBiblePage::DeleteTable(CString TableName)
{
	if(IsAppData == FALSE)
		return FALSE;    // no point in continuing if database DNE
	

	try{

if (m_pRs)
	{
		if(m_pRs->State == adStateOpen)		m_pRs->Close();				
		m_pRs.Release();
		m_pRs = NULL;
	}
	
	if(m_piAdoRecordBinding)
	 {
		m_piAdoRecordBinding->Release();
		 m_piAdoRecordBinding = NULL;
	}

	if(m_pCatalog == NULL)
	{
		HRESULT hr = S_OK;
		TESTHR(hr = m_pCatalog.CreateInstance(__uuidof(ADOX::Catalog)));
		m_pCatalog->PutActiveConnection(m_strConnection.AllocSysString() );
	}


	/* delete table from the reading plan */
	m_pCatalog->Tables->Delete(TableName.AllocSysString() );
	m_pCatalog->Tables->Refresh();

	return TRUE;


	}

	catch(...)
    {
        AfxMessageBox(_T("Error occured in DeleteTable...."));
		return FALSE;
    }



}


void CDailyBiblePage::GenerateError(HRESULT hr, PWSTR pwszDescription)
{

    CString strError;

     // Format and display the error message
     strError.Format(_T("Run-time error `%d (%x)'"), hr, hr);
     strError += _T("\n\n");
     strError += pwszDescription;

     AfxMessageBox(strError);


}

void CDailyBiblePage::UpdateBoundData()
{

	if(IsAppData == FALSE)
		return ;    // no point in continuing if database DNE

	try {

	if ( _tcscmp(ReadingDate, m_rsRecSet.m_szDate) != 0 )
      _tcscpy(m_rsRecSet.m_szDate, ReadingDate);

	if ( _tcscmp(isRead , m_rsRecSet.m_szRead)   != 0      )
      _tcscpy(m_rsRecSet.m_szRead, isRead);

	if ( _tcscmp(Data , m_rsRecSet.m_szText)   != 0      )
      _tcscpy(m_rsRecSet.m_szText, Data);

	}

	   // Any errors?
     catch (_com_error &e)
     {
		
         // Generate an error message
         GenerateError(e.Error(), e.Description());

	 }

}


/* helper function for adding a new record to access database */
void CDailyBiblePage::AddNew()
{
	if(IsAppData == FALSE)
		return ;    // no point in continuing if database DNE

	try
     {
		  
         // Update the current record
         m_piAdoRecordBinding->Update(&m_rsRecSet);
         // Can we add a new record?
         if (m_pRs->Supports(adAddNew))
         {
             // Create a blank record
             CreateBlankRecord();
			
             // Add the blank record
             m_piAdoRecordBinding->AddNew(&m_rsRecSet);
             // Move to the last record
			 if(m_pRs->EndOfFile == FALSE)
            m_pRs->MoveLast();
         }
     }
     // Any errors?
     catch (_com_error &e)
     {
         // Generate an error message
		
         GenerateError(e.Error(), e.Description());
     }

}


/* helper function that creates an empty record in the MS access database */
void CDailyBiblePage::CreateBlankRecord()
{
	if(IsAppData == FALSE)
		return;    // no point in continuing if database DNE

	try {
    // Create the blank values to be used
		CString strBlank = _T("");
	

	 _tcscpy(m_rsRecSet.m_szDate, (LPCTSTR)strBlank);
	 _tcscpy(m_rsRecSet.m_szRead, (LPCTSTR)strBlank);
    _tcscpy(m_rsRecSet.m_szText, (LPCTSTR)strBlank);
	 
	}

	   // Any errors?
     catch (_com_error &e) // Generate an error message
	 {  GenerateError(e.Error(), e.Description());}

	 



}

/* helper function for deletion of a record from MS access database */
void CDailyBiblePage::Delete()
{
	if(IsAppData == FALSE)
		return ;    // no point in continuing if database DNE

     try
     {
         // Update the current record
         m_piAdoRecordBinding->Update(&m_rsRecSet);
         // Can we delete a record?
         if (m_pRs->Supports(adDelete))
         {
                 // Delete the record
                 m_pRs->Delete(adAffectCurrent);
                 // Move to the previous record
                 m_pRs->MovePrevious();
            
         }



     }
     // Any errors?
     catch (_com_error &e) // Generate an error message
	 {  GenerateError(e.Error(), e.Description());}

	 

}





/* helper function for the MS access database */
void CDailyBiblePage::RefreshBoundData()
{
	if(IsAppData == FALSE)
	return;    // no point in continuing if database DNE
	
	try {

		if (adFldOK == m_rsRecSet.lDateStatus)
         // Copy the value
        ReadingDate = m_rsRecSet.m_szDate;
     else
         // Otherwise, set the value to 0
         ReadingDate = _T("");


		if (adFldOK == m_rsRecSet.lReadStatus)
         // Copy the value
         isRead.Format(_T("%s"), m_rsRecSet.m_szRead);
     else
         // Otherwise, set the value to 0
        isRead.Format(_T("%s"), _T("U") );




	 	if (adFldOK == m_rsRecSet.lTextStatus)
         // Copy the value
         Data.Format(_T("%s"), m_rsRecSet.m_szText);
     else
         // Otherwise, set the value to 0
        Data.Format(_T("%s"), _T("") );

	}

	   // Any errors?
     catch (_com_error &e)
     {
		
         // Generate an error message
         GenerateError(e.Error(), e.Description());

	 }

}






/* Queries the database to retrieve a string of verses for given date*/
void CDailyBiblePage::GetReadingData(CString date)
{
	if(IsAppData == FALSE)
	{
		Data = _T("");
		return;    // no point in continuing if database DNE
	}

	CString d;
	
	try
	{

	
	if (m_pRs->BOF == FALSE)  m_pRs->MoveFirst();
	RefreshBoundData();

	CString last = ReadingDate.Mid(4,4);
	if(last == _T("XXXX")) d = date.Mid(0,4) + _T("XXXX");
	else d = date;


	CString tofind;
	tofind.Format(_T("ReadingDate='%s'"), d);
	m_pRs->Find(tofind.AllocSysString() , 0, ADOCG::adSearchForward);  
   	RefreshBoundData();
	if(d.Compare(ReadingDate) == 0)	 return;


	Data = _T("");  return;
	 

	}  // end of try block

	   // Any errors?
     catch (_com_error &e)
     {   // Generate an error message
         GenerateError(e.Error(), e.Description());
	 }

	

}


/* Delete reading data for a particular date */
void CDailyBiblePage::DeleteReadingData(CString date)
{
	 // Delete the list name and its contents from the database
	 if (m_pRs->BOF == FALSE)
	 m_pRs->MoveFirst();


	 CString tofind;
	tofind.Format(_T("ReadingDate='%s'"), date);
	m_pRs->Find(tofind.AllocSysString() , 0, ADOCG::adSearchForward);  
	RefreshBoundData();

	if( ReadingDate == date) 
	{
	 Delete();
	 m_pRs->MoveNext();
	}
	
}

/* save the entry to Data.mdb database */
void CDailyBiblePage::SaveReadingData(CString date, CString readStatus, CString readingdata) 
{
	
		if(IsAppData == FALSE)
		return ;    // no point in continuing if database DNE

			CString d1 = date, d2 = date;
			d2 = date.Mid(0,4) + _T("XXXX");                     // month + date + any year

			
	try {
		// Update the current record
		if(m_piAdoRecordBinding)
      m_piAdoRecordBinding->Update(&m_rsRecSet);

	 if(VARIANT_FALSE == m_pRs->BOF)
	 m_pRs->MoveFirst();
	

	BOOL RecordFound = FALSE;

	CString tofind;
	tofind.Format(_T("ReadingDate='%s'"), d1);
	m_pRs->Find(tofind.AllocSysString() , 0, ADOCG::adSearchForward);  
   	RefreshBoundData();

	if(ReadingDate.Compare(d1) == 0) RecordFound = TRUE;
	
	else {
		if(VARIANT_FALSE == m_pRs->BOF) m_pRs->MoveFirst();
		
		tofind.Format(_T("ReadingDate='%s'"), d2);
		m_pRs->Find(tofind.AllocSysString() , 0, ADOCG::adSearchForward);  
   		RefreshBoundData();
		
		if(ReadingDate.Compare(d1) == 0) RecordFound = TRUE;
	}



	if(RecordFound == TRUE)
	{
		Data = readingdata;
		isRead = readStatus;
		UpdateBoundData();	
		m_piAdoRecordBinding->Update(&m_rsRecSet);
		
	}


	// if the record is not there, lets add a new record
	else if (RecordFound == FALSE) {		
	AddNew();

	Data = readingdata;
	ReadingDate = date;
	isRead = readStatus;
	
	UpdateBoundData();
	m_piAdoRecordBinding->Update(&m_rsRecSet);
	
	}

	}

	   // Any errors?
     catch (_com_error &e)
     {         // Generate an error message
         GenerateError(e.Error(), e.Description());
	 }



	
}
/* Make a list of reading plan tables in the database */
void CDailyBiblePage::AddPlanNames()
{

	   planNames.RemoveAll();
	 
		if(IsAppData == FALSE)
		return ;    // no point in continuing if database DNE

     

		try{

			if(m_pCatalog == NULL)
			{
				HRESULT hr = S_OK;
				TESTHR(hr = m_pCatalog.CreateInstance(__uuidof(ADOX::Catalog)));
				m_pCatalog->PutActiveConnection(m_strConnection.AllocSysString() );
			}


			/* Get a list of reading plan */
			long count = m_pCatalog->Tables->GetCount();
			ADOX::_TablePtr curTable = NULL;
			ADOX::_ColumnPtr curColumn = NULL;
			ADOX::ColumnsPtr pColumns = NULL;
			ADOX::TablesPtr pTables = m_pCatalog->Tables;
			CString tName, cName;

			if(!pTables) return;
		
			for(long i = 0; i < count; i++)
			{

				curTable = NULL;
				tName = _T("");
				cName = _T("");
				pColumns = NULL;
				curColumn = NULL;

			// get the name of the current table
			curTable = pTables->Item[i];			
			if(curTable) tName.Format(_T("%s"), (LPCTSTR) curTable->GetName()); 

			// get the name of column ("ReadingDate"?)
			if(curTable) pColumns = curTable->GetColumns();
			if(pColumns && pColumns->GetCount() > 2) curColumn = pColumns->GetItem(long(2)); 
			if(curColumn) cName.Format(_T("%s"), (LPCTSTR) curColumn->GetName()); 
	
			
			if( cName.Compare(_T("ReadingDate")) == 0)	{  planNames.Add( tName );   }
			

			}


		}  // end of the try block



		   // Any errors?
     catch (_com_error &e)
     {         // Generate an error message
         GenerateError(e.Error(), e.Description());
	
	 }


		   // Any errors?
    catch(...)
    {
        AfxMessageBox(_T("Error occured in adding plan names...."));
    }





}

 /* Select a different reading plan   */
void CDailyBiblePage::SelectTable(CString tableName)
{

	if(IsAppData == FALSE)
	return ;    // no point in continuing if database DNE
   

	 try {

		if (m_pRs)
		{
			if(m_pRs->State == adStateOpen)		m_pRs->Close();				
			m_pRs.Release();
			m_pRs = NULL;
		}
	
	 // Create the record set object
	  m_pRs.CreateInstance(__uuidof(Recordset));


	 if(m_piAdoRecordBinding)
	 {
		 m_piAdoRecordBinding->Release();
		 m_piAdoRecordBinding = NULL;
	 }


	
	  m_strCmdText.Format(_T("SELECT * FROM [%s]"), tableName); 
	
	 // Open the new record set object
     m_pRs->Open((LPCTSTR)m_strCmdText, (LPCTSTR)m_strConnection, 
            adOpenDynamic, adLockOptimistic, adCmdUnknown);

	
	 // Get a pointer to the record binding interface
         if (FAILED(m_pRs->QueryInterface(__uuidof(IADORecordBinding),
                 (LPVOID *)&m_piAdoRecordBinding)))
             _com_issue_error(E_NOINTERFACE);


		  // Bind the record class to the record set
		     m_piAdoRecordBinding->BindToRecordset(&m_rsRecSet);

		RefreshBoundData();


		// if there are zero records, add a record
		if (m_pRs->BOF && m_pRs->EndOfFile)
		{
			m_pRs->AddNew();
			m_pRs->Fields->GetItem(long(0))->PutValue(_T("0")); 
			m_pRs->Fields->GetItem(long(1))->PutValue(_T("0")); 
			m_pRs->Fields->GetItem(long(2))->PutValue(_T("0")); 
			m_pRs->Update();
		}

		
     }


     // Any errors?
     catch (_com_error &e)
     {
         // Display the error
         GenerateError(e.Error(), e.Description());
     }



}

/* Update total number of readings and the number already read by the user */
void CDailyBiblePage::ComputePercentComplete()
{

	if(IsAppData == FALSE)
		return ;    // no point in continuing if database DNE

	try {
		// Update the current record
		if(m_piAdoRecordBinding)
      m_piAdoRecordBinding->Update(&m_rsRecSet);

	 if(VARIANT_FALSE == m_pRs->BOF)
	 m_pRs->MoveFirst();

	numRead = 0;
	numTotal = 0;

    while(VARIANT_FALSE == m_pRs->EndOfFile)
	{
		RefreshBoundData();
		numTotal++;
		if( isRead == _T("R"))  numRead++;
		m_pRs->MoveNext();
	
	}
	}



	  // Any errors?
     catch (_com_error &e)
     {
         // Display the error
         GenerateError(e.Error(), e.Description());
     }


	

}

void CDailyBiblePage::CompactDatabase()
{
	CString filename = path;

	CDaoDatabase db;
	CString tempFile = filename;
	tempFile.Replace(_T("Data.mdb"), _T("DataTemp.mdb"));
	
    // close the database
	try {	

	if (m_pRs)
	{
		if(m_pRs->State == adStateOpen)		m_pRs->Close();				
		m_pRs.Release();
		m_pRs = NULL;
	}
	
	if(m_piAdoRecordBinding)
	 {
		m_piAdoRecordBinding->Release();
		 m_piAdoRecordBinding = NULL;
	}

	if(m_pCatalog) 
	{	
		m_pCatalog->PutRefActiveConnection(NULL);
		m_pCatalog = NULL;
	}
	
	 

	}

 // Any errors?
     catch (_com_error &e)
     {
         // Display the error
         GenerateError(e.Error(), e.Description());
     }

	
    // compact the database
	try
	{
		
	db.m_pWorkspace->CompactDatabase(filename, tempFile , dbLangGeneral);
	CFile::Remove(filename);

	db.m_pWorkspace->CompactDatabase(tempFile,filename , dbLangGeneral);
	CFile::Remove(tempFile); // delete the data temp file


	}
	catch (CDaoException *e)
	{
	AfxMessageBox (e->m_pErrorInfo->m_strDescription);
	e->Delete();
	}
}



void CDailyBiblePage::OnDestroy()
{
	CPropertyPage::OnDestroy();

	
	FILE* h_file = _tfopen(path, _T("r"));
	fseek(h_file, 0, SEEK_END);
	long size = ftell(h_file);
	fclose(h_file);

	if(size > 15728640) CompactDatabase();   // > 15 MB?

}
